using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing;
using System.ComponentModel;
using System.Reflection;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using XMas;
using WinFormsContentLoading;


namespace XMasEditor 
{
    public class XMasBinder : SerializationBinder
    {
        private List<Assembly> m_AssemblyList;

        public XMasBinder(List<Assembly> AssemblyList)
        {
            m_AssemblyList = new List<Assembly>(AssemblyList);
        }

        public override Type BindToType(string assemblyName, string typeName)
        {
            Type type = null;
            string shortName = assemblyName.Split(',')[0];
            Assembly[] lasms = AppDomain.CurrentDomain.GetAssemblies();

            foreach (Assembly lasm in lasms)
            //foreach (Assembly lasm in m_AssemblyList)
            {
                if (shortName == lasm.FullName.Split(',')[0])
                {
                    type = lasm.GetType(typeName);
                    break;
                }
            }
            return type;
        }
    }

    public class AnimControlData 
    {
        public AnimationControls.AnimNodeControl AnimControl;
        public XMas.AnimationNode AnimNode;      // Cached
        public System.Drawing.Point              Position;


        public AnimControlData() {}
    }

    public class AnimationSystemEditor 
    {
        public delegate void ControlDataDelegate(AnimControlData AnimData);
        public event ControlDataDelegate OnCreateGraphicalControl;


        private Dictionary<Guid, AnimControlData>   _AnimControlMap;
        private System.Windows.Forms.Control        _controlParent;
        private XMas.XMAnimationSystem _XMAnimationSystem;

        // Asembly pluggins list
        public List<Assembly> m_AssemblyList;

        // Content build
        private ContentManager _ContentManager;
        private ContentBuilder _ContentBuilder;

        // Graphics data
        private Model  _CurrentModel;
        private string _sModelPath;


        public AnimationSystemEditor(System.Windows.Forms.Control ParentControl, ContentManager ContentManager)         
        {
            _AnimControlMap = new Dictionary<Guid, AnimControlData>();
            _controlParent = ParentControl;
            _XMAnimationSystem = new XMas.XMAnimationSystem();
            m_AssemblyList = new List<Assembly>();
            _ContentBuilder = new ContentBuilder();
            _ContentManager = ContentManager;
            _sModelPath = "";
            _CurrentModel = null;
        }


        # region Properties

        public XMas.XMAnimationSystem XMAnimationSystem
        {
            get { return _XMAnimationSystem; }
        }

        public Model CurrentModel
        {
            get { return _CurrentModel; }
        }

        #endregion


        #region Private Functions

        private AnimControlData AddAnimControl(System.Drawing.Point initialPosition, XMas.AnimationNode AnimNode, bool bSetParent)
        {
            AnimControlData controlData = new AnimControlData();
            // Create control
            controlData.AnimControl = new AnimationControls.AnimNodeControl();            
            controlData.AnimControl.Location = initialPosition;
            controlData.Position = initialPosition;

            // Events
            controlData.AnimControl.OnValueChanged += this.ControlChangeValue;

            AnimNode.onPropertiesChanges += HandleControlPropertiesChanges;
            // Link in control (to get Node from control)
            controlData.AnimControl.Tag = AnimNode.ID;
            controlData.AnimNode = AnimNode;
            // Special types
            bool bStartNode = AnimNode as XMas.AnimNode_Start != null;
            bool bAnimNode = AnimNode as XMas.AnimNode_Animation != null;

            // Special properties
            controlData.AnimControl.AllowCreateAndDestroyChildrens = !AnimNode.FixedChildren;
            controlData.AnimControl.AllowInComingConections = !bStartNode;
            controlData.AnimControl.ShowSlider = !bStartNode;
            if (bStartNode)
            {
                controlData.AnimControl.ColorPanelStart = System.Drawing.Color.SteelBlue;
                controlData.AnimControl.ColorPanelEnd = System.Drawing.Color.LightSteelBlue;
                controlData.AnimControl.ColorTitleStart = System.Drawing.Color.SteelBlue;
                controlData.AnimControl.ColorTitleEnd = System.Drawing.Color.SteelBlue;
            }
            if (bAnimNode)
            {
                controlData.AnimControl.ColorPanelStart = System.Drawing.Color.DarkSeaGreen;
                controlData.AnimControl.ColorPanelEnd = System.Drawing.Color.LightSeaGreen;
                controlData.AnimControl.ColorTitleStart = System.Drawing.Color.DarkSeaGreen;
                controlData.AnimControl.ColorTitleEnd = System.Drawing.Color.DarkSeaGreen;
            }

            // Set the skining for animations
            XMas.AnimNode_Animation NodeAnimation = AnimNode as XMas.AnimNode_Animation;
            if (NodeAnimation != null && _XMAnimationSystem.SkiningData != null)
            {
                NodeAnimation.SkeletonData = _XMAnimationSystem.SkiningData;
            }


            // Add to link controls and nodes list           
            _AnimControlMap.Add(AnimNode.ID, controlData);            
            RecreateControl(controlData);

            // Scale
            if (_XMAnimationSystem.ScaleFactor != 0 && controlData.AnimControl != null)
            {
                SizeF scale = CalcScale(0, _XMAnimationSystem.ScaleFactor);
                controlData.AnimControl.Scale(scale);
                controlData.AnimControl.Location = initialPosition;
            }

            // Set slider
            controlData.AnimControl.SliderValue = controlData.AnimNode.GetEditorValue();
            
            if (OnCreateGraphicalControl != null)
                OnCreateGraphicalControl(controlData);


            if (bSetParent)
                controlData.AnimControl.Parent = _controlParent;

            return controlData;
        }

        private SizeF CalcScale(int ipreviusScale, int iNewScale)
        {
            float fScale = iNewScale - ipreviusScale;
            float fBaseScale = 0.9f;

            // To Up
            if (fScale > 0)
                fBaseScale = 1.0f / 0.9f;
            fScale = (float)System.Math.Pow(fBaseScale, System.Math.Abs(fScale));
            SizeF sScale = new SizeF(fScale, fScale);
            return sScale;
        }

        private void ClearAllControls()
        {
            // Clear old controls
            if (_AnimControlMap != null)
            {
                foreach (KeyValuePair<Guid, AnimControlData> AnimDataPair in _AnimControlMap)
                {
                    if (AnimDataPair.Value.AnimControl != null)
                        AnimDataPair.Value.AnimControl.Dispose();
                }
                _AnimControlMap.Clear();
            }
        }

        private void RecreateMap()
        {
            _AnimControlMap.Clear();
            foreach (XMas.AnimationNode AnimNode in _XMAnimationSystem.AnimNodeList)
            {
                // Create control
                System.Drawing.Point Location = new System.Drawing.Point(AnimNode.EditorX, AnimNode.EditorY);
                // Add to map
                AddAnimControl(Location, AnimNode, true);
            }
            if (_controlParent != null)
                _controlParent.Refresh();
        }

        private void DeleteBranchRecursive(AnimControlData AnimData)
        {
            if (AnimData != null && AnimData.AnimNode != null)
            {
                // Todos los hijos
                foreach (XMas.AnimationNodeItem itemNode in AnimData.AnimNode.ItemList)
                {
                    // Buscamos el destino
                    if (itemNode.AnimNodeDestination != null)
                    {
                      AnimControlData AnimDataChild = GetAnimDataFromNode(itemNode.AnimNodeDestination);
                      DeleteBranchRecursive(AnimDataChild);
                    }
                }
                DeleteNode(AnimData);
            }
        }

        private void CloneBranchRecursive(AnimControlData AnimData, XMas.AnimationNode parentClone, int iIdxParent, List<AnimControlData> selectedList, bool bCreateChilds)
        {
            if (AnimData == null || AnimData.AnimNode == null)
              return;

            // Add this node
            System.Drawing.Point vNewPoint = new System.Drawing.Point(AnimData.AnimControl.Location.X + 10, AnimData.AnimControl.Location.Y + 10);
            AnimControlData thisNode = AddNode(vNewPoint, AnimData.AnimNode.GetType().FullName, !bCreateChilds);
            if (thisNode != null && thisNode.AnimNode != null)
            {
                // Add to selected
                selectedList.Add(thisNode);
                thisNode.AnimControl.BringToFront();

                CloneProperties(AnimData.AnimNode, thisNode.AnimNode);

                
                // Create links
                if (parentClone != null)
                  thisNode.AnimNode.CreateNodeConnection(parentClone, iIdxParent);
                
                // Add childrens
                for (int iIdx = 0; iIdx < AnimData.AnimNode.ItemList.Count; iIdx++)
                {
                    // If we need to add item
                    XMas.AnimationNodeItem itemNode = AnimData.AnimNode.ItemList[iIdx];
                    if (thisNode.AnimNode.ItemList.Count == iIdx)
                        thisNode.AnimNode.AddChild(itemNode.Text, 0);
                    else
                        thisNode.AnimNode.ItemList[iIdx].Text = itemNode.Text;

                    // Check if has a destination
                    if (itemNode.AnimNodeDestination != null && bCreateChilds)
                    {
                        AnimControlData AnimDataChild = GetAnimDataFromNode(itemNode.AnimNodeDestination);
                        CloneBranchRecursive(AnimDataChild, thisNode.AnimNode, iIdx, selectedList, true);
                    }
                }

                
                // Recreate
                // Set slider
                thisNode.AnimControl.SliderValue = AnimData.AnimControl.SliderValue;
                thisNode.AnimNode.HandleSliderMove(AnimData.AnimControl.SliderValue);
                RecreateControl(thisNode);
            }
            
        }

        private void CloneProperties(XMas.AnimationNode srcNode, XMas.AnimationNode destNode)
        {
            if (srcNode.GetType() != destNode.GetType())
                return;

            PropertyInfo[] myPropertyInfo = srcNode.GetType().GetProperties();
            for (int i = 0; i < myPropertyInfo.Length; i++)
            {
                if (myPropertyInfo[i].CanWrite)
                    myPropertyInfo[i].SetValue(destNode, myPropertyInfo[i].GetValue(srcNode, null), null);
            }
    
        }

        private void ImportSourceModel(string strPath)
        {
            frmWait wait = new frmWait();
            wait.Show(_controlParent);
            _controlParent.Refresh();
            wait.Refresh();
            wait.BringToFront();
            _controlParent.Cursor = Cursors.WaitCursor;

            _CurrentModel = null;
            _ContentManager.Unload();
            _XMAnimationSystem.ModelPath = "";

            // Tell the ContentBuilder what to build.
            _ContentBuilder.Clear();
            // TODO: Hacer dependiente del plugin
            //_ContentBuilder.Add(openFileDialog1.FileName, "Model", null, "SkinnedModelProcessor");
            // TODO: Better dependency
            string strExtension = Path.GetExtension(strPath).ToUpper();
            if (strExtension == ".CSF")
                _ContentBuilder.Add(strPath, "Model", "CCald3DImporter", "CCald3DProcess");
            else if (strExtension == ".FBX")
                _ContentBuilder.Add(strPath, "Model", "FbxImporter", "SkinnedModelProcessor");

            // SkinnedModel needs SkinnedModel.fx, copy them
            string CurrPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            File.Copy(CurrPath + @".\Content\SkinnedModel.xnb", _ContentBuilder.BuildDirectory + @"\SkinnedModel.xnb", true);
            File.Copy(CurrPath + @".\Content\SkinnedModel.fx", _ContentBuilder.BuildDirectory + @"\SkinnedModel.fx", true);

            // Build this new model data.
            string buildError = _ContentBuilder.Build();
            _controlParent.Refresh();

            if (string.IsNullOrEmpty(buildError))
            {
                // If the build succeeded, use the ContentManager to
                // load the temporary .xnb file that we just created.
                _ContentManager.RootDirectory = _ContentBuilder.OutputDirectory;
                _CurrentModel = _ContentManager.Load<Model>("Model");
            }
            else
            {
                // If the build failed, display an error message.
                _controlParent.Cursor = Cursors.Default;
                MessageBox.Show(buildError, "Error");
            }
            _controlParent.Cursor = Cursors.Default;
            wait.Close();
            wait.Dispose();            
        }

        private void ImportCompiledModel(string strPath)
        {
            _ContentManager.Unload();
            _ContentManager.RootDirectory = Path.GetDirectoryName(strPath);
            string strFileName = Path.GetFileNameWithoutExtension(strPath);
            // SkinnedModel needs SkinnedModel.fx, copy them
            //string CurrPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            //File.Copy(CurrPath + @".\Content\SkinnedModel.xnb", _ContentManager.RootDirectory + @"\SkinnedModel.xnb", true);

            try
            {
                _CurrentModel = _ContentManager.Load<Model>(strFileName);
            }
            catch (Exception e)
            {
                _CurrentModel = null;
                MessageBox.Show(e.Message + "\r\n" + e.InnerException, "Load fails");                
            }           

            // Delete file
            //File.Delete(_ContentManager.RootDirectory + @"\SkinnedModel.xnb");
        }


        #endregion


        #region Controls Functions

        public void TranslateControls(System.Drawing.Point vDeltaMove)
        {
          foreach (KeyValuePair<Guid, AnimControlData> AnimDataPair in _AnimControlMap)
          {
            if (AnimDataPair.Value.AnimControl != null)
            {
              System.Drawing.Point vNewLocation = new System.Drawing.Point(AnimDataPair.Value.AnimControl.Location.X + vDeltaMove.X, AnimDataPair.Value.AnimControl.Location.Y + vDeltaMove.Y);
              AnimDataPair.Value.AnimControl.Location = vNewLocation;              
            }
          }
          _controlParent.Refresh();
        }

        public void SelectControlsInRectangle(System.Drawing.Rectangle selecRectangle, List<AnimControlData> selectedList)
        {
            foreach (KeyValuePair<Guid, AnimControlData> AnimDataPair in _AnimControlMap)
            {
                if (AnimDataPair.Value.AnimControl != null)
                {
                    System.Drawing.Rectangle controlRectangle = new System.Drawing.Rectangle(AnimDataPair.Value.AnimControl.Location, AnimDataPair.Value.AnimControl.Size);
                    if (selecRectangle.IntersectsWith(controlRectangle))
                    {
                        // Add only the unselected nodes
                        if (!selectedList.Contains(AnimDataPair.Value))
                        {
                            AnimDataPair.Value.AnimControl.CaptionColor = System.Drawing.Color.Yellow;
                            selectedList.Add(AnimDataPair.Value);
                        }
                    }
                }
            }
            _controlParent.Refresh();
        }

        public void ScaleControls(bool ToUp)
        {
            int iNewScale = _XMAnimationSystem.ScaleFactor;
            if (ToUp && iNewScale < 3)
                iNewScale++;
            else if(!ToUp && iNewScale > -5)
                iNewScale--;
            
            if (iNewScale != _XMAnimationSystem.ScaleFactor)
            {
                SizeF sScale = CalcScale(_XMAnimationSystem.ScaleFactor, iNewScale);
                foreach (KeyValuePair<Guid, AnimControlData> AnimDataPair in _AnimControlMap)
                {
                    if (AnimDataPair.Value.AnimControl != null)
                        AnimDataPair.Value.AnimControl.Scale(sScale);
                }
                _XMAnimationSystem.ScaleFactor = iNewScale; 
                _controlParent.Refresh();
            }
        }

        public void ResetView()
        {
            // Get start, otehrwire first node
            XMas.AnimationNode TargetNode = _XMAnimationSystem.StartNode;
            if (TargetNode == null)
            {
                if (_XMAnimationSystem.AnimNodeList.Count > 1)
                    TargetNode = _XMAnimationSystem.AnimNodeList[0];
            }

            if (TargetNode != null)
            {
                AnimControlData animData = GetAnimDataFromNode(TargetNode);
                if (animData != null && animData.AnimControl != null)
                {
                    System.Drawing.Point pDelta = new System.Drawing.Point(
                        3 - animData.AnimControl.Location.X, 3 - animData.AnimControl.Location.Y);
                    TranslateControls(pDelta);
                }                
            }
        }

        public void RecreateControl(AnimControlData AnimData)
        {
            AnimData.AnimControl.TitleText = AnimData.AnimNode.Name;

            // we need to update the visual control
            AnimData.AnimControl.RemoveAllElements();

            for (int iIdx = 0; iIdx < AnimData.AnimNode.ItemList.Count; iIdx++)
            {
                AnimData.AnimControl.AddNewElement(AnimData.AnimNode.ItemList[iIdx].Text);
            }
            AnimData.AnimControl.RecalculateElements();
        }

        public void DeleteBranch(AnimControlData AnimData)
        {
            DeleteBranchRecursive(AnimData);
        }

        public void CloneBranch(AnimControlData AnimData, List<AnimControlData> selectedList)
        {
            CloneBranchRecursive(AnimData, null, 0, selectedList, true);
            // Set parent
            foreach (AnimControlData animData in selectedList)
            {
                animData.AnimControl.Parent = _controlParent;
                animData.AnimControl.BringToFront();
            }
        }

        public void CloneNodes(List<AnimControlData> selectedList)
        {
            List<AnimControlData> nodeList = new List<AnimControlData>(selectedList);
            selectedList.Clear();
            foreach (AnimControlData AnimData in nodeList)           
                CloneBranchRecursive(AnimData, null, 0, selectedList, false);
            nodeList.Clear();
        }

        #endregion


        #region Public Get Funtions

        public AnimControlData GetAnimDataFromControl(AnimationControls.AnimNodeControl pAnimControl)
        {
            Guid guid = (Guid)pAnimControl.Tag;
            AnimControlData resultNode = null;
            if (_AnimControlMap.ContainsKey(guid))
                resultNode = _AnimControlMap[guid];

            return resultNode;
        }

        public AnimControlData GetAnimDataFromNode(XMas.AnimationNode AnimNode)
        {
            AnimControlData resultNode = null;
            if (_AnimControlMap.ContainsKey(AnimNode.ID))
                resultNode = _AnimControlMap[AnimNode.ID];

            return resultNode;
        }

        #endregion


        # region Adding and deling nodes

        public AnimControlData AddNode(System.Drawing.Point initialPosition, string AnimNodeType, bool bSetParent)
        {
            AnimControlData controlData = null;
            
            // List all assembly list
            foreach (Assembly asm in m_AssemblyList)
            {
                Type type = asm.GetType(AnimNodeType, false, true);
                if (type != null)
                {
                    object obj = asm.CreateInstance(AnimNodeType);
                    XMas.AnimationNode AnimNode = (XMas.AnimationNode)obj;
                    // If the system allow add
                    if (_XMAnimationSystem.AddNode(AnimNode))
                        controlData = AddAnimControl(initialPosition, AnimNode, bSetParent);
                    break;
                }
            }
            return controlData;
        }

        public bool DeleteNode(AnimControlData data)
        {
            bool bResult = true;

            // Delete anim node
            Guid id = data.AnimNode.ID;
            if (data.AnimNode != null)
                bResult = _XMAnimationSystem.DeleteNode(data.AnimNode);
            if (bResult)
            {
                if (data.AnimControl != null)
                {
                    data.AnimControl.Dispose();
                    bResult = _AnimControlMap.Remove(id);
                }
            }
            return bResult;
        }

        #endregion


        #region Draw

        public void DrawAnimationsTime()
        {
            // All nodes
            foreach (AnimControlData animData in _AnimControlMap.Values)
            {
                // Check animation node
                if (animData.AnimNode as AnimNode_Animation != null)
                    animData.AnimControl.SliderValue = animData.AnimNode.GetEditorValue();
            }
        }

        public void DrawAllConections(Graphics graph)
        {
            // Draw all conections
            System.Drawing.Point vStart = new System.Drawing.Point(0, 0);
            System.Drawing.Point vEnd = new System.Drawing.Point(0, 0);
            // All nodes
            foreach (AnimControlData animData in _AnimControlMap.Values)
            {
                // All items
                for (int iItems = 0; iItems < animData.AnimNode.ItemList.Count; iItems++)
                {
                    XMas.AnimationNodeItem Item = animData.AnimNode.ItemList[iItems];
                    // Color by weight
                    int iColorValue = (int)(255.0f * Item.AcumWeigth);
                    System.Drawing.Color lineColor = System.Drawing.Color.FromArgb(iColorValue, iColorValue, 0);

                    // Change item color
                    animData.AnimControl.SetElementColor(iItems, lineColor);

                    if (Item != null && Item.AnimNodeDestination != null)
                    {
                        // Get destination control
                        AnimControlData animDataDestination = GetAnimDataFromNode(Item.AnimNodeDestination);
                        if (animDataDestination != null)
                        {
                            vStart = animData.AnimControl.GetConectionIdxPosition(iItems);
                            vEnd =  animDataDestination.AnimControl.GetInitialConectionPosition();
                            DrawCurve(graph, vStart, vEnd, lineColor);
                        }
                    }
                }   // Items
            }       // Animation nodes
        }

        public void DrawCurve(Graphics graph, System.Drawing.Point vStart, System.Drawing.Point vEnd, System.Drawing.Color color)
        {
            // Creamos punto intermedio (solo si es distinto)            
            Pen penCurrent = new Pen(color, 1.5f);
            if (vStart != vEnd)
            {
                Vector2 vDir = new Vector2();
                Vector2 vStartM = new Vector2(vStart.X, vStart.Y);
                vDir = new Vector2(vEnd.X, vEnd.Y) - vStartM;

                float fDistance = vDir.Length();
                vDir.Normalize();
                Vector2 vPerpendicular = new Vector2(vDir.Y, -vDir.X);
                // Si es menor cambiamos
                if (vStart.Y > vEnd.Y)
                    vPerpendicular *= -1.0f;

                // Punto medio
                vStartM += (vDir * fDistance / 2.0f);
                // El perpendicular
                vStartM += vPerpendicular * 10.0f;
                System.Drawing.Point pMiddle = new System.Drawing.Point((int)vStartM.X, (int)vStartM.Y);
                System.Drawing.Point[] pt = { vStart, pMiddle, vEnd };
                graph.DrawCurve(penCurrent, pt);
            }
            else
            {
                System.Drawing.Point[] pt = { vStart, vEnd };
                graph.DrawCurve(penCurrent, pt);
            }
        }

        #endregion


        # region Handlers

        private void ControlChangeValue(AnimationControls.AnimNodeControl pSourceNode, int iNewValue)
        {
            AnimControlData AnimData = GetAnimDataFromControl(pSourceNode);
            if (AnimData != null && AnimData.AnimNode != null)
            {
                AnimData.AnimNode.HandleSliderMove(iNewValue);
                if (pSourceNode.Parent != null)
                    pSourceNode.Parent.Refresh();
            }
        }

        private void HandleControlPropertiesChanges(XMas.AnimationNode AnimNode)
        {
            AnimControlData AnimData = GetAnimDataFromNode(AnimNode);
            if (AnimData != null && AnimData.AnimNode != null)
                RecreateControl(AnimData);
        }

        # endregion


        #region Load and Save

        public void ImportModel(string strPath)
        {
            // Check if compiled model xnb
            string strExtension = Path.GetExtension(strPath);
            if (strExtension.ToUpper() == ".XNB")
                ImportCompiledModel(strPath);                              
            else
                ImportSourceModel(strPath);  

            CSkeletonData skinningData = null;
            _sModelPath = "";            
            if (_CurrentModel != null)
            {
                _sModelPath = strPath;
                skinningData = _CurrentModel.Tag as CSkeletonData;
                if (skinningData == null)
                    throw new InvalidOperationException("This model does not contain a SkinningData tag.");
            }
            _XMAnimationSystem.SkiningData = skinningData;
            _XMAnimationSystem.ModelPath = strPath;
        }

        public void NewFile()
        {
            // Dispose current controls
            ClearAllControls();
            _XMAnimationSystem = new XMas.XMAnimationSystem();
            if (_CurrentModel != null)
            {
                CSkeletonData skinningData = _CurrentModel.Tag as CSkeletonData;
                if (skinningData == null)
                    throw new InvalidOperationException("This model does not contain a SkinningData tag.");
                _XMAnimationSystem.SkiningData = skinningData;
                _XMAnimationSystem.ModelPath = _sModelPath;                
            }                    
        }

        public void LoadFromFile(string FileName)
        {
            if (File.Exists(FileName))
            {
                Stream myStream = File.OpenRead(FileName);
                if (myStream != null)
                {
                    // Dispose current controls
                    ClearAllControls();

                    XmlSerializer xmlSerializer = new XmlSerializer(typeof(XMas.XMAnimationSystem));
                    try
                    {
                        // Add plugins        
                        XMas.XMAnimationSystem.SetAssemblyList(m_AssemblyList);
                        _XMAnimationSystem = (XMas.XMAnimationSystem)xmlSerializer.Deserialize(myStream);
                        // Import model
                        if (_sModelPath != _XMAnimationSystem.ModelPath || _CurrentModel == null)
                            ImportModel(_XMAnimationSystem.ModelPath);
                        // Set model
                        if (_CurrentModel != null)
                        {
                            CSkeletonData skinningData = _CurrentModel.Tag as CSkeletonData;
                            if (skinningData == null)
                                throw new InvalidOperationException("This model does not contain a SkinningData tag.");
                            _XMAnimationSystem.SkiningData = skinningData;
                        }
                        RecreateMap();
                    }                    
                    catch (Exception e)
                    {
                        MessageBox.Show(e.Message + "\r\n" + e.InnerException, "Load fails");
                    }                    
                    myStream.Close();
                }
            }
        }

        public void SaveToFile(string FileName)
        {
            Stream myStream = File.OpenWrite(FileName);
            if (myStream != null)
            {
                // Update locations
                foreach (KeyValuePair<Guid, AnimControlData> AnimDataPair in _AnimControlMap)
                {
                    if (AnimDataPair.Value.AnimControl != null && AnimDataPair.Value.AnimNode != null)
                    {
                        AnimDataPair.Value.AnimNode.EditorX = AnimDataPair.Value.AnimControl.Location.X;
                        AnimDataPair.Value.AnimNode.EditorY = AnimDataPair.Value.AnimControl.Location.Y;
                    }
                }

                //IFormatter formatter = new BinaryFormatter();
                XmlSerializer serializer = new XmlSerializer(typeof(XMas.XMAnimationSystem));
                serializer.Serialize(myStream, _XMAnimationSystem);
                myStream.Close();
            }
        }

        // DEPRECATED
        public void SaveToFileBinary(string FileName)
        {
            Stream myStream = File.OpenWrite(FileName);
            if (myStream != null)
            {
                // Update locations
                foreach (KeyValuePair<Guid, AnimControlData> AnimDataPair in _AnimControlMap)
                {
                    if (AnimDataPair.Value.AnimControl != null && AnimDataPair.Value.AnimNode != null)
                    {
                        AnimDataPair.Value.AnimNode.EditorX = AnimDataPair.Value.AnimControl.Location.X;
                        AnimDataPair.Value.AnimNode.EditorY = AnimDataPair.Value.AnimControl.Location.Y;
                    }
                }

                IFormatter formatter = new BinaryFormatter();
                formatter.Serialize(myStream, _XMAnimationSystem);
                myStream.Close();
            }
        }

        // DEPRECATED
        public void LoadFromFileBinary(string FileName, Model currentModel)
        {
            if (File.Exists(FileName))
            {
                Stream myStream = File.OpenRead(FileName);
                if (myStream != null)
                {
                    // Dispose current controls
                    ClearAllControls();

                    IFormatter formatter = new BinaryFormatter();
                    formatter.Binder = new XMasBinder(m_AssemblyList);
                    try
                    {
                        _XMAnimationSystem = (XMas.XMAnimationSystem)formatter.Deserialize(myStream);
                        if (currentModel != null)
                        {
                            CSkeletonData skinningData = currentModel.Tag as CSkeletonData;
                            if (skinningData == null)
                                throw new InvalidOperationException("This model does not contain a SkinningData tag.");
                            _XMAnimationSystem.SkiningData = skinningData;
                        }
                        RecreateMap();
                    }
                    catch (Exception e)
                    {
                        MessageBox.Show(e.Message, "Load fails");
                    }

                    myStream.Close();
                }
            }
        }
        #endregion
    }
}
